from flask import request, jsonify, _request_ctx_stack
from werkzeug.local import LocalProxy
import logging
from functools import wraps
import traceback
from marshmallow import Schema

logger = logging.getLogger(__name__)

current_schema_instance = LocalProxy(lambda: getattr(_request_ctx_stack.top, 'current_schema_instance', None))

# 请求参数合法性校验
def request_arg_check(schema_instance: Schema, many: bool=False, location: str="json"):
    def wrapper(fun):
        @wraps(fun)
        def decorator(*args, **kwargs):
            try:
                # 检验请求参数是否合法，合法后保存
                data = None
                errors = None
                if location == "json":
                    data, errors = schema_instance.load(request.json, many=many)
                if location == "args":
                    data, errors = schema_instance.load(request.args, many=many)
                if location == "form":
                    data, errors = schema_instance.load(request.form, many=many)
                if errors:
                    logger.info("request_arg_check error:{}".format(errors))
                    return jsonify(dict(message=dict(status=403, code=403, message=str(errors))))
                _request_ctx_stack.top.current_schema_instance = data
            except Exception as err:
                return jsonify(dict(message=dict(status=403, code=403, message=str(err))))
            return fun(*args, **kwargs)
        return decorator
    return wrapper


def exception_response(status=500, code=500, message="error happened"):
    def wrapper(fun):
        @wraps(fun)
        def decorator(*args, **kwargs):
            try:
                # 执行过程中如果有异常，则处理异常
                return fun(*args, **kwargs)
            except Exception as err:
                logger.info("{} arg:{}, kwargs:{} error happened: {}".format(fun, args, kwargs, err))
                logger.info(traceback.format_exc())
                return jsonify(dict(message=dict(status=status, code=code, message=str(err))))
        return decorator
    return wrapper
